#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define A2E     0
#define E2A     1

static unsigned char ascii_ebcdic_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
   0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x3F, 0x3F,
   0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
   0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
   0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
   0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
   0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
   0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
   0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
   0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
   0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
   0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x6A, 0x5F, 0x6D,
   0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
   0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
   0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x4A, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
};

static unsigned char ebcdic_ascii_tab[] =
{
   0x20, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x20, 0x20,
   0x10, 0x11, 0x12, 0x13, 0x00, 0x15, 0x08, 0x00,
   0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x17, 0x1B,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
   0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x04,
   0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x00,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x5b, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
   0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5e,
   0x2D, 0x2F, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x5D, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
   0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
   0x71, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
   0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   0x48, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
   0x51, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x5C, 0x20, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
   0x59, 0x5A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   0x38, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0xFF
};


unsigned char ConvChar(unsigned char c, int Dir)
{
   if( Dir == A2E )
      return ascii_ebcdic_tab[c];
   else
      return ebcdic_ascii_tab[c];
}

void MemDump(FILE *f, const void *Buf, int Len, bool Ebcdic, int Offset)
{
   int i, n;
   char AsciiStr[17];
   unsigned char c;
   const unsigned char *p = (const unsigned char*)Buf;

   for( n = 0; n < Len; n += 16 )
   {
      AsciiStr[16] = '\0';
      fprintf(f, "%08x  ", Offset + n);
      for( i = 0; i < 16; i++, p++ ){
         if( i == 8 )
            fprintf(f, " ");
         if( n + i >= Len ){
            AsciiStr[i] = ' ';
            fprintf(f, "   ");
         }
         else{
            if( Ebcdic )
               c = ConvChar(*p, E2A);
            else
               c = *p;
            if( c > '~' || c < ' ' )
               AsciiStr[i] = '.';
            else
               AsciiStr[i] = c;
            fprintf(f, " %02x", *p);
         }
         if( i == 15 ){
            fprintf(f, "   ");
            fprintf(f, "%s\n", AsciiStr);
         }
      }
   }
}

static void work(FILE *f, bool Ebcdic, int RecLen)
{
   int i, Offset;
   int RecNo;
   int Len;
   char *Buf;

   if ( RecLen == 0 )
   {
      Len = 256;
   }
   else
   {
      Len = RecLen;
   }

   Buf = (char*)malloc(Len);

   for( RecNo = 0, Offset = 0; ; )
   {
      i = fread(Buf, 1, Len, f);
      if ( i <= 0 )
      {
         break;
      }
      RecNo++;
      if ( RecLen != 0 )
      {
         printf("RECORD NUMBER = %d\n", RecNo);
      }
      MemDump(stdout, Buf, i, Ebcdic, Offset);
      Offset += i;
   }

   free(Buf);
}

int main(int argc, char *argv[])
{
   FILE *f;
   int i;
   int RecLen = 0;
   bool Ebcdic;

   Ebcdic = false;

   for ( i = 1; ; i++ )
   {
      if ( argc > i && strcmp(argv[i], "-e") == 0 )
      {
         Ebcdic = true;
         continue;
      }
      if ( argc > i && memcmp(argv[i], "-l", 2) == 0 )
      {
         RecLen = atoi(argv[i] + 2);
         continue;
      }
      break;
   }

   if ( argc == i )
   {
      work(stdin, Ebcdic, RecLen);
      return 0;
   }

   for( ; i < argc; i++ ){
      f = fopen(argv[i],"rb");
      if( f == NULL ){
         fprintf(stderr, "can not open %s\n", argv[i]);
         return 1;
      }
      work(f, Ebcdic, RecLen);
      fclose(f);
   }

   return 0;
}
